package com.nidu.demo.tenant.executor.command;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.nidu.demo.common.enums.RoleCodeEnum;
import com.nidu.demo.role.gateway.RoleGateway;
import com.nidu.demo.role.gateway.RoleMenuGateway;
import com.nidu.demo.role.model.Role;
import com.nidu.demo.role.model.RoleCriteria;
import com.nidu.demo.tenant.dto.TenantPackageUpdateCmd;
import com.nidu.demo.common.enums.StatusEnum;
import com.nidu.demo.tenant.ability.TenantPackageDomainService;
import com.nidu.demo.tenant.convertor.TenantPackageConvertor;
import com.nidu.demo.tenant.dto.TenantPackageCO;
import com.nidu.demo.tenant.gateway.TenantGateway;
import com.nidu.demo.tenant.gateway.TenantPackageGateway;
import com.nidu.demo.tenant.model.Tenant;
import com.nidu.demo.tenant.model.TenantCriteria;
import com.nidu.demo.tenant.model.TenantPackage;
import com.nidu.demo.tenant.util.TenantUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 租户套餐更新命令执行器
 *
 * @author auto
 */
@Component
@RequiredArgsConstructor
public class TenantPackageUpdateCmdExe {

    private final TenantPackageConvertor convertor;

    private final TenantPackageGateway gateway;

    private final TenantGateway tenantGateway;

    private final RoleGateway roleGateway;

    private final RoleMenuGateway roleMenuGateway;

    private final TenantPackageDomainService domainService;

    public SingleResponse<TenantPackageCO> execute(TenantPackageUpdateCmd cmd) {
        // 1. 转换为领域对象
        TenantPackage tenantPackage = TenantPackage.update(cmd.getId(), cmd.getName(), cmd.getSortOrder());

        // 2. 校验对象
        domainService.validateDuplicate(tenantPackage.getName(), tenantPackage.getId());

        // 3. 调用网关保存
        TenantPackage save = this.updateTenantPackage(tenantPackage, cmd.getMenuIds());
        // 4. 转换为DTO返回
        TenantPackageCO tenantPackageCO = convertor.toClientObject(save);

        return SingleResponse.of(tenantPackageCO);
    }

    public Response updateStatus(Long id, StatusEnum status) {
        gateway.updateStatus(id, status.getValue());
        return Response.buildSuccess();
    }

    @Transactional
    private TenantPackage updateTenantPackage(TenantPackage tenantPackage, Set<Long> menuIds){
        TenantPackage save = gateway.update(tenantPackage);

        // 如果菜单发生变化，则修改每个租户的菜单
        if (!CollUtil.isEqualList(save.getMenuIds(), menuIds)) {
            //修改该套餐包下的所有租户
            TenantCriteria criteria = new TenantCriteria();
            criteria.setPackageId(save.getId());
            List<Tenant> tenants = tenantGateway.listByCondition(criteria);

            tenants.forEach(tenant -> TenantUtils.execute(tenant.getId(), () -> {
                // 获取该租户的所有角色
                List<Role> roles = roleGateway.listByCondition(new RoleCriteria());
                roles.forEach(role -> {
                    // 如果是租户管理员，重新分配其权限为租户套餐的权限
                    if (Objects.equals(role.getRoleCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) {
                        roleMenuGateway.rebindRoleMenus(role.getId(), menuIds);
                        return;
                    }
                    // 如果是其他角色，则去掉超过套餐菜单的权限
                    Set<Long> roleMenuIds = roleMenuGateway.getMenuIdsByRoleId(role.getId());
                    roleMenuIds = CollUtil.intersectionDistinct(menuIds, roleMenuIds);
                    roleMenuGateway.rebindRoleMenus(role.getId(), roleMenuIds);
                });
            }));
            save = gateway.update(new TenantPackage().setId(save.getId()).setMenuIds(menuIds));
        }

        return save;
    }
}
